#include <sched.h>
#include <sys/socket.h>
#include <assert.h>


inline bool PTThreadCreate(PTThreadEntry *pThreadEntry, void *pThreadParam, PTThread *pThreadOut)
{
	return ::pthread_create(pThreadOut, NULL, pThreadEntry, pThreadParam) == 0;
}

inline bool PTThreadWait(PTThread *pThread)
{
	void *retval;
	return ::pthread_join(*pThread, &retval) == 0;
}

inline bool PTSpinLockCreate(PTSpinLock *pSpinLock)
{
	pSpinLock->bIsLocked = 0U;
	return true;
}

inline bool PTSpinLockEnterBusy(PTSpinLock *pSpinLock)
{
	while (::__sync_lock_test_and_set(&pSpinLock->bIsLocked, 1U) != 0U)
		continue;

	return true;
}

inline bool PTSpinLockEnterSleep(PTSpinLock *pSpinLock)
{
	while (::__sync_lock_test_and_set(&pSpinLock->bIsLocked, 1U) != 0U)
		::sched_yield();
	
	return true;
}

inline bool PTSpinLockLeave(PTSpinLock *pSpinLock)
{
	uint32_t rtval = ::__sync_lock_test_and_set(&pSpinLock->bIsLocked, 0U);
	assert(rtval == 1U);

	return false;
}

inline bool PTSpinLockDestory(PTSpinLock *pSpinLock)
{
	return true;
}

inline bool PTSemaphoreCreate(uint32_t iInitialValue, PTSemaphore *pSemaphoreOut)
{
	return ::sem_init(pSemaphoreOut, 0, iInitialValue) == 0;
}

inline bool PTSemaphorePassern(PTSemaphore *pSemaphore)
{
	return ::sem_wait(pSemaphore) == 0;
}

inline bool PTSemaphoreVrijgeven(PTSemaphore *pSemaphore)
{
	return ::sem_post(pSemaphore) == 0;
}

inline bool PTSemaphoreDestory(PTSemaphore *pSemaphore)
{
	return ::sem_destroy(pSemaphore) == 0;
}

inline bool PTSocketStreamPair(PTSocket *pSocketFirst, PTSocket *pSocketSecond)
{
	int sv[2];
	int rtval = ::socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
	if (rtval == -1)
	{
		return false;
	}
	else
	{
		pSocketFirst->m_fd = sv[0];
		pSocketSecond->m_fd = sv[1];
		return true;
	}
}

inline bool PTSocketDatagramPair(PTSocket *pSocketFirst, PTSocket *pSocketSecond)
{
	int sv[2];
	int rtval = ::socketpair(AF_UNIX, SOCK_DGRAM, 0, sv);
	if (rtval == -1)
	{
		return false;
	}
	else
	{
		pSocketFirst->m_fd = sv[0];
		pSocketSecond->m_fd = sv[1];
		return true;
	}
}
inline bool PTSocketWriteVector(PTSocket *pSocket, PTSocketIOVector SocketIOVector[], uint32_t nCount, uint32_t *pNumberOfBytesWritten)
{
	ssize_t rtval = ::writev(pSocket->m_fd, SocketIOVector, static_cast<int>(nCount));
	if (rtval == -1)
	{
		return false;
	}
	else
	{
		*pNumberOfBytesWritten = static_cast<uint32_t>(rtval);
		return true;
	}
}
inline bool PTSocketReadVector(PTSocket *pSocket, PTSocketIOVector SocketIOVector[], uint32_t nCount, uint32_t *pNumberOfBytesRead)
{
	ssize_t rtval = ::readv(pSocket->m_fd, SocketIOVector, static_cast<int>(nCount));
	if (rtval == -1)
	{
		return false;
	}
	else
	{
		*pNumberOfBytesRead = static_cast<uint32_t>(rtval);
		return true;
	}
}

inline int64_t PTTickCount()
{
	timeval tv;
	int rtval = ::gettimeofday(&tv, NULL);
	assert(rtval == 0);
	return 1000000LL * static_cast<int64_t>(tv.tv_sec) + static_cast<int64_t>(tv.tv_usec);
}

inline int64_t PTTickFrequency()
{
	return 1000000LL;
}

//uint64_t mask;
//int rtval = sched_getaffinity(0, sizeof(uint64_t), reinterpret_cast<cpu_set_t *>(&mask));
//assert(rtval == 0);